// Boolean
const isDone: boolean = false;

// Number
const decLiteral: number = 6;

// String
const myName: string = 'Tom';

// Array
const list: number[] = [1, 2, 3];
const list2: Array<number> = [1, 2, 3]; // 泛型

// Enum number 数字枚举自增
enum Direction {
  Up = 1,
  Down,
  Left,
  Right
}

const dir: Direction = Direction.Up;
console.log('dir', dir);

// Enum string 字符串枚举
enum Direction2 {
  Up = 'Up',
  Down = 'Down',
  Left = 'Left',
  Right = 'Right'
}

// Any
let notSure: any = 4;

// unknown unknown 类型只能被赋值给 any 类型和 unknown 类型本身
let value: unknown;
value = true;
value = 1;
value = 'hello';
value = {};
value = [];

// Tuple 元组
let tupleType: [string, boolean];
tupleType = ['1', true];

// Void void 类型像是与 any 类型相反，它表示没有任何类型。
// 当一个函数没有返回值时，你通常会见到其返回值类型是 void
function warnUser(): void {
  console.log('This is my warning message');
}

// Null 和 Undefined
let u: undefined = undefined;
let n: null = null;

// Never never 类型表示的是那些永不存在的值的类型。
// 例如，never 类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型
function error(message: string): never {
  throw new Error(message);
}

// 泛型
function reverse<k>(arr: k[]): k[] {
  return arr.reverse();
}

// 交叉类型
function extend<T extends object, U extends object>(first: T, second: U): T & U {
  const result = <T & U>{};
  for (let id in first) {
    (<T>result[id]) = first[id] as T[keyof T];
  }
  for (let id in second) {
    if (!result.hasOwnProperty(id)) {
      (<U>result[id]) = second[id] as U[keyof U];
    }
  }
  return result;
}

const x = extend({ a: 'hello' }, { b: 42 });
console.log('x', x);

// 联合类型
function padLeft(value: string, padding: string | number) {
  if (typeof padding === 'number') {
    return Array(padding + 1).join(' ') + value;
  }
  if (typeof padding === 'string') {
    return padding + value;
  }
  throw new Error(`Expected string or number, got '${padding}'.`);
}

// 类型别名
type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver): Name {
  if (typeof n === 'string') {
    return n;
  } else {
    return n();
  }
}
